#ifndef __BUOLA_GUI_X11_CX11DISPLAY_H__
#define __BUOLA_GUI_X11_CX11DISPLAY_H__

#include <buola/gui/x11/auto.h>

#include <X11/Xlib.h>

namespace buola { namespace gui { namespace x11 {

class CX11Display
{
private:
    enum EStatus
    {
        STATUS_UNKNOWN=(1<<0),
        STATUS_RUNNING=(1<<1),
        STATUS_OPEN=(1<<2),
        STATUS_REMOTE=(1<<3),
        STATUS_LOCAL=(1<<4),
        STATUS_HAVECMD=(1<<5)
    };

    DECLARE_FRIEND_ENUM_BITOPS(EStatus)

    class SAtoms
    {
    public:
        SAtoms(CX11Display *pDisplay);

    //Types
        Atom mMultiple;
        Atom mTargets;
        Atom mUTF8;
        Atom mCompound;
        Atom mTextPlain;
        Atom mTextUrilist;

    //Base
        Atom mProtocols;
        Atom mState;
        Atom mHints;
        Atom mWMCommand;
        Atom mWMClass;
        Atom mName;
        Atom mIconName;
        Atom mWMClientMachine;
        Atom mLocaleName;
        Atom mMotifHints;

//WM protocols
        Atom mDeleteWindow;
        Atom mTakeFocus;
        Atom mChangeState;
        Atom mClientLeader;
        Atom mContextHelp;

//Root window properties
        Atom mNetSupported;
        Atom mNetClientList;
        Atom mNetClientListStacking;
        Atom mNetNumberOfDesktops;
        Atom mNetDesktopViewport;
        Atom mNetDesktopGeometry;
        Atom mNetCurrentDesktop;
        Atom mNetDesktopNames;
        Atom mNetActiveWindow;
        Atom mNetWorkArea;
        Atom mNetSupportingWMCheck;
        Atom mNetVirtualRoots;
        Atom mNetDesktopLayout;
        Atom mNetShowingDesktop;

//Root window commands
        Atom mNetCloseWindow;
        Atom mNetMoveResizeWindow;
        Atom mNetWMMoveResize;

//Client properties
        Atom mNetWMName;
        Atom mNetWMVisibleName;
        Atom mNetWMIconName;
        Atom mNetWMVisibleIconName;
        Atom mNetWMDesktop;
        Atom mNetWMWindowType;
        Atom mNetWMState;
        Atom mNetWMStrut;
        Atom mNetWMIconGeometry;
        Atom mNetWMIcon;
        Atom mNetWMPID;
        Atom mNetWMHandledIcons;
        Atom mNetWMUserTime;
        Atom mNetFrameExtents;
        
//Window manager protocols
        Atom mNetWMPing;
        Atom mNetWMSyncRequest;
        Atom mNetWMSyncRequestCounter;

//WM states
        Atom mNetWMStateModal;
        Atom mNetWMStateSticky;
        Atom mNetWMStateMaxVert;
        Atom mNetWMStateMaxHorz;
        Atom mNetWMStateShaded;
        Atom mNetWMStateSkipTaskbar;
        Atom mNetWMStateSkipPager;
        Atom mNetWMStateHidden;
        Atom mNetWMStateFullScreen;
        Atom mNetWMStateAbove;
        Atom mNetWMStateBelow;
        Atom mNetWMStateDemandsAttention;

//WM types
        Atom mNetWMWindowTypeDesktop;
        Atom mNetWMWindowTypeDock;
        Atom mNetWMWindowTypeToolbar;
        Atom mNetWMWindowTypeMenu;
        Atom mNetWMWindowTypeUtility;
        Atom mNetWMWindowTypeSplash;
        Atom mNetWMWindowTypeDialog;
        Atom mNetWMWindowTypeDropdownMenu;
        Atom mNetWMWindowTypePopupMenu;
        Atom mNetWMWindowTypeTooltip;
        Atom mNetWMWindowTypeNotification;
        Atom mNetWMWindowTypeCombo;
        Atom mNetWMWindowTypeDND;
        Atom mNetWMWindowTypeNormal;
        Atom mNetWMWindowTypeKDEOverride;

        Atom mNetWMWindowOpacity;

//startup notification
        Atom mNetStartupID;

//composite manager flags
        Atom mSupportingCMCheck;
        Atom mBuolaDockWindow;
        Atom mBuolaThumbnail;

        Atom mBuolaWMExtensions;
        Atom mBuolaCustomDeco;

//drag and drop
        Atom mDndAware;
        Atom mDndTypeList;
        Atom mDndActionList;
        Atom mDndActionDescription;
        Atom mDndProxy;
        Atom mDndEnter;
        Atom mDndPosition;
        Atom mDndStatus;
        Atom mDndLeave;
        Atom mDndDrop;
        Atom mDndFinished;
        Atom mDndActionCopy;
        Atom mDndActionMove;
        Atom mDndActionLink;
        Atom mDndActionAsk;
        Atom mDndActionPrivate;

//Selection atoms
        Atom mClipboard;
        Atom mPrimary;
        Atom mSecondary;
        Atom mDndSelection;

//Buola atoms
        Atom mBuolaTransfer;

//XEmbedAtoms
        Atom mXEmbedInfo;
        Atom mXEmbed;

        Atom mStandard2x2;
        Atom mStandard4x4;
        Atom mStandard128x128;
    };

protected:
    CX11Display();
    CX11Display(const std::string&,const std::string&);
    CX11Display(Display*);
    ~CX11Display();

protected:
    void CalcStatus();
    void CalcDisplayInfo();

public:
    bool IsRunning();

    void Launch();
    void Open();
    void Close();

    void StartIM();

public:
    int GetConnectionNumber()   {   return mConnectionNumber;   }
    Display *GetDisplay()       {   return mDisplay;            }
    Window GetDefaultRoot()     {   return mDefaultRoot;        }
    const std::string &GetName()    {   return mDisplayName;        }
    Screen *GetScreen()         {   return mScreen;             }
    int GetScreenNumber()       {   return mScreenNumber;       }
    Visual *GetVisual()         {   return mVisual;             }
    int GetDepth()              {   return mDepth;              }
    Colormap &GetColormap()     {   return mColormap;           }
    XIC &GetXIC()               {   return mXIC;                }
    XIM &GetXIM()               {   return mXIM;                }

    const SAtoms &Atoms()       {   return *mAtoms;             }

    Atom GetAtom(const std::wstring&,bool=false);
    std::wstring GetAtomName(Atom);
    bool SetWindowProperty(Window,Atom,Atom,int,int,const void*);
    int GetWindowProperty(Window,Atom,Atom,void**,int=1024);
    bool SetWindowProperty(Window,Atom,Atom,const std::wstring&);
    bool GetWindowProperty(Window,Atom,Atom,std::wstring&);
    bool SetWindowProperty(Window,Atom,Atom,const std::string&);
    bool GetWindowProperty(Window,Atom,Atom,std::string&);
    bool SetWindowProperty(Window,Atom,const std::vector<Atom> &);
    bool GetWindowProperty(Window,Atom,std::vector<Atom> &);
    bool SetWindowProperty(Window,Atom,int);
    bool SetWindowPropertyAsAtom(Window,Atom,Atom);
    bool GetWindowProperty(Window,Atom,int*);
    bool HasWindowProperty(Window,Atom);

    void SendClientMessage(Window pSrc,Window pDest,Atom pAtom,
                int l1=0,int l2=0,int l3=0,int l4=0,int l5=0,
                long pMask=NoEventMask,bool pPropagate=false);
public:
    static CX11Display *AddDisplay(const std::string&,const std::string&);
    static CX11Display *AddDisplay(Display*);
    static CX11Display *AddDefaultDisplay();

private:
    static std::vector<CX11Display*> mDisplays;

    int mConnectionNumber;
    Display *mDisplay;
    Window mDefaultRoot;
    int mScreenNumber;
    Screen *mScreen;
    Visual *mVisual;
    int mDepth;
    Colormap mColormap;

    std::string mDisplayName;
    std::string mDisplayCmd;
    EStatus mStatus;

    XIM mXIM;
    XIC mXIC;

    SAtoms *mAtoms;
};

/*namespace x11*/ } /*namespace gui*/ } /*namespace buola*/ }

#endif
